 page
*******************************************************
* program/data relocation routine is driven by a table
* describing program, vectors, and data segments.  the
* table has the general format:
*  (1)command:     0= zero destinaton range. 
*                  1= move data to from src to dst. 
*                  2= high address ref tbl, relocate & move.
*                  3= lo-hi addr ref tbl, relocate & move.
*                  4= program, relocate & move.
*                 >4= end of table.
*  (2)dest addr:   address of where segment is to be moved. 
*  (2)byte count:  length of segment. 
*  (2)source addr: start address segment to be operated on,
*                  n/a if type=0, code does not have to be
*                  assembled at this address.
*  (1)segments:    number of address ranges to be tested
*                  and altered, n/a if type=0 or 1.
*                  limit and offset lists should each 
*                  contain segments+1 (s) bytes.
*  (s)limitlow:    list of low page addresses to be tested.
*  (s)limithigh:   list of high page addresses to be tested.
*  (s)offset:      list of amounts to be added if 
*                  low & high limits have been met.
* 
* on entry: x=table address low, y=table address high 
* on exit:  carry clear if no error; else carry set, 
*           x=addrlo, y=addrhi of error causing source. 
*           a=0 if input table error, =$ff if illegal opcode.
*******************************************************
 skp 1
reloc stx rtbl ;save address of control table
 sty rtbl+1
*
**************** see note #68 *****************
*
* patch for the gs rom... force the intcxrom bit off
*  to guarantee that the internal/external status of 
*  the slots are set per the control panel.
*
* the patch is placed here not because it belongs here;
*  it is here because it must be executed before whchrom and
*  the code between $2000 and the end of greet must stay
*  where it is (to avoid altering the location of the splashscreen
*  bytes which are patched by prodos/16!).
*
statereg equ $c068
*
 lda statereg
 and #$fe
 sta statereg ;we have forced off intcxrom
*
************************************************
*
 skp 1
rloop ldy #0 ;get relocation command 
 lda (rtbl),y
 cmp #5 ;if 5 or greater then done...
 bcs rlend ;branch if done.
 tax
 iny ;move destination address to
 lda (rtbl),y ; zero page for indirect access.
 sta dst
 iny
 lda (rtbl),y
 sta dst+1
 iny
 lda (rtbl),y ;also the length (byte count)
 sta cnt ; of the destination area.
 iny
 lda (rtbl),y
 sta cnt+1
 bmi rlerr ;branch if >=32k
 txa ;request to zero out destination?
 beq zero ;branch if it is.
 page
 iny
 lda (rtbl),y ;now get the source address.
 sta src
 sta cde ;src is used for the move, cde is
 iny ; used for relocation.
 clc ;add length to get final address
 adc cnt
 sta ecde
 lda (rtbl),y
 sta src+1
 sta cde+1
 adc cnt+1
 sta ecde+1 
 dex ;now that set-up is done, test for 'move'
 beq movem ;branch if move only (no relocation).
 stx wsize ;save element size (1,2,3).
 iny
 lda (rtbl),y ;now get the number of ranges
 sta sgcnt ; that are valid relocation target addresses.
 tax ;separate serial range groups into tables.
rlimlo iny
 lda (rtbl),y ;transfer low limits to 'limlo' table.
 sta limlo,x
 dex
 bpl rlimlo
 ldx sgcnt
rlimhi iny
 lda (rtbl),y ;transfer high limits to 'limhi' table.
 sta limhi,x
 dex
 bpl rlimhi
 ldx sgcnt
rofset iny
 lda (rtbl),y ;transfer offsets to 'ofset' table.
 sta ofset,x
 dex
 bpl rofset
 skp 1
 jsr adjtbl ;adjust 'rtbl' to point at next spec.
 ldx wsize ;test for machine code relocation.
 cpx #3
 beq rlcode ;branch if program relocation
 jsr reladr ;otherwise, relocate addresses in
rlend1 jsr move ; one or two byte tables, then move to destination.
 jmp rloop ;do next table entry... 
 skp 1
rlend clc
 rts
 skp 1
rlerr jmp tblerr 
 skp 1
rlcode jsr rlprog ;go relocate machine code references.
 jmp rlend1
 page 
zero jsr adjtbl ;adjust 'rtbl' pointer to next entry.
 lda #0 ;fill destination range with zeros.
 ldy cnt+1 ;is it at least a page?
 beq zpart branch if less than 256 bytes.
 tay
zero1 sta (dst),y
 iny
 bne zero1
 inc dst+1 ;bump to next page.
 dec cnt+1
 bne zero1 ;branch if more pages to clear.
zpart ldy cnt ;any bytes left to zero?
 beq zeroed ;branch if not.
 tay
zpart1 sta (dst),y
 iny
 cpy cnt
 bcc zpart1
zeroed jmp rloop ;do next thing in table.
 skp 1
movem jsr adjtbl
 jmp rlend1 
 skp 2
adjtbl tya ;add previous table length to 'rtbl'
 sec ; to get position of next entry in table.
 adc rtbl
 sta rtbl
 bcc adjtbl1
 inc rtbl+1
adjtbl1 rts
 skp 2
move lda src+1 ;determine if move is up, down,
 cmp dst+1 ; or not at all.
 bcc movup ;branch if definitely up...
 bne movdn ;branch if definitely down...
 lda src
 cmp dst
 bcc movup ;branch if definitely up...
 bne movdn ;branch if definitely down...
 rts ;otherwise, don't move nutin.
 page 
movup ldy cnt+1 ;calc highest page of move up.
 tya
 clc
 adc src+1
 sta src+1 ; and adjust src & dst accordingly.
 tya
 clc
 adc dst+1
 sta dst+1
 ldy cnt ;move partial page first.
 beq mvup2 ;branch if no partial pages.
mvup1 dey
 lda (src),y
 sta (dst),y
 tya ;end of page transfer?
 bne mvup1
mvup2 dec dst+1
 dec src+1
 dec cnt+1 ;done with all pages?
 bpl mvup1 ;branch if not.
 rts
 skp 1
movdn ldy #0 
 lda cnt+1 ;partial page move only?
 beq mvdn2 ;branch if less than a page to be moved.
mvdn1 lda (src),y
 sta (dst),y
 iny
 bne mvdn1
 inc dst+1 ;bump addresses
 inc src+1
 dec cnt+1 ;more pages?
 bne mvdn1 ;branch if more pages.
mvdn2 lda cnt ;move partial page.
 beq mvdn4 ;branch if no more to move.
mvdn3 lda (src),y
 sta (dst),y
 iny
 cpy cnt
 bne mvdn3
mvdn4 rts ;all done...
 page 
reladr ldy wsize ;determine 1 or 2 byte reference
 dey
 lda (cde),y
 jsr adjadr ;relocate reference.
 lda wsize ;update and test 'cde' pointer
 jsr adjcde
 bcc reladr ;branch if more to do.
 rts
 skp 1
rlprog ldy #0 ;fetch next opcode.
 lda (cde),y
 jsr oplen ;determine if it's a 3 byte instruction.
 beq rperr ;branch if not an opcode.
 cmp #3
 bne rlprg1
 ldy #2
 jsr adjadr ;relocate address
 lda #3
rlprg1 jsr adjcde ;update and test 'cde' for done.
 bcc rlprog ;loop if more to do.
 rts
*
* error handling...
*
rperr pla ;return bad code address 
 pla ;first un-do stack
 ldx cde
 ldy cde+1
 lda #$ff ;indicate bad opcode.
 sec ;indicate error
 rts
*
tblerr equ * ;return table address error
 ldx rtbl
 ldy rtbl+1
 lda #0 ;indicate input table error
 sec
 rts
*
*
adjadr lda (cde),y ;get page address
 ldx sgcnt ; and test against limits.
adjad1 cmp limlo,x ;is it >= low?
 bcc adjad2 ;branch if not.
 cmp limhi,x ;is it =< highest page limit.
 bcc adjad3 ;branch if it is.
 beq adjad3
adjad2 dex ;try next limit set.
 bpl adjad1
 rts ;return without adjustment.
adjad3 clc ;add offset to form relocated
 adc ofset,x ; page address.
 sta (cde),y ;and replace old address with result.
 rts
 skp 2
adjcde clc ;update 'cde' pointer
 adc cde
 ldy cde+1
 bcc adcde1 ;branch if not page cross.
 iny ;update high order address too.
adcde1 cpy ecde+1 ;has all code/data been processed?
 bcc adcde2 ;branch if definitely not.
 cmp ecde ;if carry results set, end of code.
adcde2 sta cde
 sty cde+1 ;save updated values.
 rts ;return result (carry set=done).
 page 
oplen pha ;form index to table and which 2-bit group.
 and #3 ;low 2 bits specify group.
 tay
 pla
 lsr a ;upper 6 bits specify byte in table.
 lsr a
 tax
 lda opcodln,x
nxgroup dey ;is opcode length in lowest 2 bits of acc?
 bmi rtnlen ;branch if it is.
 lsr a
 lsr a ;shift to next group
 bne nxgroup ;if len=0 then error...
rtnlen and #3 ;strip other garbage 
 rts ;if z-flg true, then error!!! 
* 
*
* the following table contains the length of each
* machine instruction (in two-bit groups).
*
opcodln dfb $09,$28,$19,$3c
 dfb $0a,$28,$0d,$3c
 dfb $0b,$2a,$19,$3f
 dfb $0a,$28,$0d,$3c
 dfb $09,$28,$19,$3f
 dfb $0a,$28,$0d,$3c
 dfb $09,$28,$19,$3f
 dfb $0a,$28,$0d,$3c
 dfb $08,$2a,$11,$3f
 dfb $0a,$2a,$1d,$0c
 dfb $2a,$2a,$19,$3f
 dfb $0a,$2a,$1d,$3f
 dfb $0a,$2a,$19,$3f
 dfb $0a,$28,$0d,$3c
 dfb $0a,$2a,$19,$3f
 dfb $0a,$28,$0d,$3c
 skp 2
wsize dfb 0
sgcnt dfb 0 
limlo dfb 0,0,0,0,0,0,0,0 
limhi dfb 0,0,0,0,0,0,0,0 
ofset dfb 0,0,0,0,0,0,0,0 
zzzend ds $2b00-*,0 
* ram disk routines follow at $2a00 (*en3 - at $2b00*)
* dfb 0 ;this byte is needed to avoid a bug in edasm(*??en3??*)
